#include "Ctrl.h"

#if Reflect_

/*
#define N 2 + 2  // 仅仅是字符串替换
#define N (2 + 2)  // 也是字符串 ，但是是（2 + 2）

#define area(x) (x) * (x) // 带参的宏定义参会当作字符串直接替换

三种特殊的符号：
##			#define Conn(x, y) x##y     // 表示连接，数字，字符串都可以
#			#define ToString(x) #x      // 就是加上双引号
#@			#define ToChar(x) #@x       //就是加上单引号， 越界会报错


*/

#include <map>
#include <string>

/// 对象创建模版函数， 用到了 c++11 的可变参数
template<class YourClass, typename ...ArgType>
void* __createObjFunc(ArgType... arg)
{
	return new YourClass(arg...);
}

/// 需要反射的类使用该宏注册
#ifndef ReflectRegister
#define ReflectRegister(YourClass, ...) \
    static int __type##YourClass = ObjFactory::regCreateObjFunc(#YourClass, (void*)&__createObjFunc<YourClass, ##__VA_ARGS__>);
#endif

/// 对象工厂，根据类名创建
class ObjFactory
{
public:
	/// 根据类名创建 BaseClass 子类的对象
	template<class BaseClass, typename ...ArgType>
	static BaseClass* createObj(const char* className, ArgType... arg)
	{
		typedef BaseClass* (*_CreateFactory)(ArgType...);

		auto& _funcMap = _GetStaticFuncMap();
		auto iFind = _funcMap.find(className);
		if (iFind == _funcMap.end())
			return nullptr;
		else
			return reinterpret_cast<_CreateFactory>(_funcMap[className])(arg...);
	}

	/// 注册“创建类的对象的工厂函数”
	static int regCreateObjFunc(const char* className, void* func)
	{
		_GetStaticFuncMap()[className] = func;
		return 0;
	}

private:
	/// 获取 函数名==>函数指针 的映射。
	static std::map<const char*, void*>& _GetStaticFuncMap()
	{
		static std::map<const char*, void*> _classMap;
		return _classMap;
	}
};




class BaseShape
{
public:
	virtual void draw() = 0;
};


class Triangle : public BaseShape
{
	std::string m_userData;
public:
	Triangle(std::string userData)
		: m_userData(userData)
	{}
	void draw() override
	{
		std::cout << "I'm Triangle," << m_userData.c_str();
	}
};
ReflectRegister(Triangle, std::string) // 注册三角形类






// 在实际使用的代码中，只需要调用 ObjFactory::createObj + 想调用的类名字符串 来获取实际的类
int main() {

	BaseShape* pBase;
	pBase = ObjFactory::createObj<BaseShape>("Rectangle");
	if (pBase != nullptr)
		pBase->draw();
	pBase = ObjFactory::createObj<BaseShape, std::string>("Triangle", "hello");
	if (pBase != nullptr)
		pBase->draw();


	return 0;
}


#endif